using System;
using System.Collections.Generic;
using Mbs.Collections;

namespace Mbs.ComponentModel.Container.Activation
{
    [Serializable]
    public class ActivatorFactory : MarshalAndDisposableObject, IActivatorFactory
    {
        private IMap<string, Func<IActivator>> Cache;
        public ActivatorFactory()
        {
            Cache = new ConcurrentMap<string, Func<IActivator>>(StringComparer.OrdinalIgnoreCase);
            Cache[ActivatorType.Default] = () => new DefaultActivator();
            Cache[ActivatorType.Instance] = () => new InstanceActivator();
            Cache[ActivatorType.Factory] = () => new DelegateActivator();
        }

        public void Register(string id, Func<IActivator> creator)
        {
            if (string.IsNullOrEmpty(id))
                throw new ArgumentNullException("id == null");

            if (Cache.ContainsKey(id))
                throw new RepeatRegistrationException("Repeat registration exception for id:" + id.ToString());

            if (creator == null)
                throw new ArgumentNullException("creator == null");

            Cache[id] = creator;
        }

        public void UnRegister(string id)
        {
            if (string.IsNullOrEmpty(id))
                throw new ArgumentNullException("id == null");

            if (!Cache.ContainsKey(id))
                throw new Exception("id:[" + id.ToString() + "] not exists");

            Cache.Remove(id);
        }

        public bool HasRegister(string id)
        {
            return Cache.ContainsKey(id);
        }


        public IActivator Create(string input)
        {
            if (string.IsNullOrEmpty(input))
                throw new ArgumentNullException("input == null");
            if (!Cache.ContainsKey(input))
                throw new Exception("activator Id:" + input + " not exists.");

            return Cache[input]();
        }

        public IActivator Create(Func<Mbs.ComponentModel.Container.Context.ICreateContext, object> creator)
        {
            if (creator == null)
                throw new ArgumentNullException("creator == null");
            var factory = Cache[ActivatorType.Factory]() as DelegateActivator;
            factory.Creator = creator;
            return factory;
        }

        protected override void Dispose(bool disposing)
        {
            Cache.Dispose();
        }
    }

    public class ActivatorType
    {
        public const string Default = "Default";
        public const string Instance = "Instance";
        public const string Factory = "Factory";
        public const string Proxy = "Proxy";
    }
}
